<?php
/**
 * polwebgis
 * 
 * This file is part of polwebgis.
 *
 * @copyright   Copyright (c) 2012 Dominik Janisch (http://www.joanneum.at)
 * @lastmodified    $LastChangedDate: 2012-03-07 09:15:12 +0000 (Wed, 07 Mar 2012) $
 * @revision    $Revision: 160 $ 
 */

require_once(PATH_TO_APP . "/components/analysis/ContiguityRegion.php");

class Analysis
{
    private $output_handler_;
    private $language_handler_;
    private $table_gateway_;

    public function __construct($singleton_registry, $table_gateway)
    {
        $this->output_handler_ = $singleton_registry->getSingleton('OutputHandler');
        $this->language_handler_ = $singleton_registry->getSingleton('LanguageHandler');
        $this->table_gateway_ = $table_gateway;
    }
    
    public function __destruct(){}
    
    private function resizeHistogram($sum, MapList &$map_list)
    {
        $ratio = $sum/1;
        $arr_tmp = $map_list->get('arr_histogram');
        foreach($arr_tmp as $key => $value)
            $arr_tmp[$key]["width_percentaged"] = round($value["width_percentaged"]/$ratio, 3);
        $map_list->set('arr_histogram', $arr_tmp);
    }
    
    public function calculateHistogram(MapList &$map_list)
    {
        $data = true;
        $map_list->set('histogram', true);
        $sum = 0;
        $arr_test = current($map_list->get('arr_histogram'));
        if(array_key_exists("width_percentaged", $arr_test))
        {
            foreach($map_list->get('arr_histogram') as $value)
                $sum += $value["width_percentaged"];
            if($sum > 1)
                $this->resizeHistogram($sum, $map_list);
        }
        else
            $data = false;
        $this->output_handler_->assignValuesToTemplate(array("histogram_data" => $data, "arr_values" => $map_list->get('arr_histogram'), "analysis_title" => $this->language_handler_->getLanguageString('analysis_histogram')));
    }
    
    public function calculateStats(MapClassProperties $map_class_properties)
    {
        $arr_values = array();
        $arr_values['mean'] = $map_class_properties->getMean();
        $arr_values['stddev'] = $map_class_properties->getStddev();
        $arr_values['min'] = $map_class_properties->getMin();
        $arr_values['max'] = $map_class_properties->getMax();
        $arr_values['n'] = $map_class_properties->getCases();
        $arr_values['sum'] = (int)($map_class_properties->getCases()*$map_class_properties->getMean());
        $this->output_handler_->assignValuesToTemplate(array("arr_values" => $arr_values, "analysis_title" => $this->language_handler_->getLanguageString('analysis_stats')));
    }
    
    public function calculateBoxPlot(MapClassProperties $map_class_properties, Classification $classification, $arr_data, $hinge, $classes, $format_handler, $is_int)
    {
        $map_class_properties->setClassWidth(4);
        $arr_quartile_breaks == array();
        $sum = 0;
        foreach($classification->getQuantileBreaks(4) as $value)
        {
            $sum += $value;
            $arr_quartile_breaks[] = $sum;
        }
        $arr_values = array();
        $arr_values['max'] = $map_class_properties->getMax();
        $arr_values['min'] = $map_class_properties->getMin();
        $arr_values['median'] = $this->calculateMedian($map_class_properties->getCases(), $arr_data);
        $arr_values['box_lower_border'] = $arr_data[$arr_quartile_breaks[0]]['value'];
        $arr_values['box_upper_border'] = $arr_data[$arr_quartile_breaks[2]-1]['value'];
        $iqr = $arr_values['box_upper_border'] - $arr_values['box_lower_border']; 
        $arr_values['box_lower_outlier'] = $arr_values['box_lower_border'] - $iqr*$hinge;
        $arr_values['box_upper_outlier'] = $arr_values['box_upper_border'] + $iqr*$hinge;
        $arr_values['top_value'] = $arr_values['max'] > $arr_values['box_upper_outlier'] ? $arr_values['max'] : $arr_values['box_upper_outlier'];
        $arr_values['bottom_value'] = $arr_values['min'] < $arr_values['box_lower_outlier'] ? $arr_values['min'] : $arr_values['box_lower_outlier'];
        $arr_values['range'] = $arr_values['top_value'] - $arr_values['bottom_value'];
        foreach($arr_data as $data)
        {
            if((float)$data['value'] < $arr_values['box_lower_outlier'])
                $arr_values['values'][] = $this->createEntry($data, $format_handler, $is_int);
            if((float)$data['value'] > $arr_values['box_upper_outlier'])
                $arr_values['values'][] = $this->createEntry($data, $format_handler, $is_int);
        }
        $map_class_properties->setClassWidth($classes);
        $this->output_handler_->assignValuesToTemplate(array("arr_values" => $arr_values));
    }
    
    public function calculateMoran(MapClassProperties $map_class_properties, $arr_data, $format_handler, $is_int, $e_id)
    {
        $arr_contiguity_regions = array();
        $z = 0;
        $m2 = 0;
        foreach($arr_data as $key => $item)
        {
            $zi = ($item['cases']-$map_class_properties->getMean())/$map_class_properties->getStddev();
            $arr_contiguity_regions[$item['gid']] = new ContiguityRegion($item['gid'], $item['region'], $item['cases'], $zi);
            $z += $zi*$zi;
        }
        unset($arr_data);
        $m2 = $z/$map_class_properties->getCases();
        $this->createContiguityMatrix($e_id, $arr_contiguity_regions);
        $moran = 0;
        foreach($arr_contiguity_regions as $contiguity_region)
            $moran += $contiguity_region->calculateLocalMoran($m2);
        $this->createScatterplotArray($arr_contiguity_regions, $format_handler, $is_int, $m2, $map_class_properties->getCases());
    }
    
    private function createContiguityMatrix($e_id, $arr_contiguity_regions)
    {
        foreach($this->table_gateway_->getContiguity($e_id) as $item)
        {   
            if($item['n_gid'] !== NULL && array_key_exists($item['gid'], $arr_contiguity_regions) && array_key_exists($item['n_gid'], $arr_contiguity_regions))
                $arr_contiguity_regions[$item['gid']]->addNeighbour($arr_contiguity_regions[$item['n_gid']]);
        }
    }
    
    private function createScatterplotArray($arr_contiguity_regions, $format_handler, $is_int, $m2, $cases)
    {
        $arr_tmp = array();
        $sum_l_moran = 0;
        foreach($arr_contiguity_regions as $key => $contiguity_region)
        {
            $sum_l_moran += $contiguity_region->calculateLocalMoran($m2);
            $arr_tmp[$key]['value'] = $contiguity_region->getStandardScore();
            $arr_tmp[$key]['n_value'] = $contiguity_region->calculateNeighbourScore();
            $arr_tmp[$key]['f_value'] = $format_handler->getOutput($contiguity_region->getCases(), $is_int);
            $arr_tmp[$key]['region'] = $contiguity_region->getName();
        }
        $moran = $sum_l_moran/$cases;
        $this->output_handler_->assignValuesToTemplate(array("arr_data" => $arr_tmp, "moran" => $moran));
        return $moran;
    }
    
    private function createEntry($arr_data, $format_handler, $is_int)
    {
        $arr_tmp = array();
        $arr_tmp['value'] = (float)$arr_data['value'];
        $arr_tmp['region'] = $arr_data['region'];
        $arr_tmp['f_value'] = $format_handler->getOutput($arr_data['value'], $is_int);
        return $arr_tmp;
    }
    
    private function calculateMedian($cases, $arr_data)
    {
        if($cases % 2 == 0)
        {
            $median = 0.5*($arr_data[($cases-1)/2]['value']+$arr_data[$cases/2]['value']);
        }
        else
        {
            $median = $arr_data[($cases+1)/2-1]['value'];
        }
        return $median;
    }
}
?>
